package com.lsh.payment.service.refund;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.dubbo.rpc.protocol.rest.support.ContentType;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lsh.payment.api.model.basevo.BaseResponse;
import com.lsh.payment.api.model.basevo.CommonResult;
import com.lsh.payment.api.model.basevo.ExceptionStatus;
import com.lsh.payment.api.model.refund.*;
import com.lsh.payment.api.service.refund.IRefundRestService;
import com.lsh.payment.core.constant.RedisKeyConstant;
import com.lsh.payment.core.exception.BusinessException;
import com.lsh.payment.core.model.payenum.PayChannel;
import com.lsh.payment.core.model.payenum.PayStatus;
import com.lsh.payment.core.model.payenum.RefundStatus;
import com.lsh.payment.core.model.payenum.RefundType;
import com.lsh.payment.core.model.payment.PayDeal;
import com.lsh.payment.core.model.refund.PayRefund;
import com.lsh.payment.core.service.payment.impl.PayDealService;
import com.lsh.payment.core.service.redis.RedisLockService;
import com.lsh.payment.core.service.refund.PayRefundOrderService;
import com.lsh.payment.core.service.refund.RefundOrderHandlerService;
import com.lsh.payment.service.BaseService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;

import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.List;

/**
 * Project Name: lsh-payment
 *
 * @author peter
 * @date 17/6/28
 * 北京链商电子商务有限公司
 * Package
 * desc:
 */
@Service(protocol = "rest", validation = "true")
@Path("refund")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({ContentType.APPLICATION_JSON_UTF_8})
public class PayRefundRestService extends BaseService implements IRefundRestService, InitializingBean {

    private final Logger logger = LoggerFactory.getLogger(PayRefundRestService.class);

    @Autowired
    private PayDealService payDealService;

    @Autowired
    private PayRefundOrderService payRefundOrderService;

    @Autowired
    private RedisLockService redisLockService;

    @Autowired
    private RefundOrderHandlerService refundOrderHandlerService;

    @Override
    public void afterPropertiesSet() throws BusinessException {

    }

    /**
     * 支付统一退款申请接口
     * @param refundRequest 下单参数
     * @return
     */
    @Override
    @POST
    @Path("apply")
    public BaseResponse refund(RefundRequest refundRequest) {
        BaseResponse baseResponse = new BaseResponse();

        refundRequest.setVenderId(this.getVenderId());

        String refundKey = MessageFormat.format(RedisKeyConstant.PAY_REFUND_TRADE_LOCK, refundRequest.getRefund_trade_id());
        try {
            logger.info("refundRequest info is " + JSON.toJSONString(refundRequest));
            //重复下单锁
            if (!redisLockService.lock(refundKey, refundRequest.getRefund_trade_id())) {
                throw new BusinessException(ExceptionStatus.E1002002.getCode(), "退款太频繁,请稍后再试");
            }
            //是否存在支付记录
            PayDeal payDeal = payDealService.queryPayDealByPayPaymentNo(refundRequest.getPay_payment_no());

            if(!this.payDealCheck(payDeal, refundRequest)){
                throw new BusinessException(ExceptionStatus.E1002002.getCode(), "参数检查错误");
            }

            PayChannel payChannel = PayChannel.getPayChannel(payDeal.getPayChannel());
            if (payChannel == null) {
                throw new BusinessException(ExceptionStatus.E2001006.getCode(), "暂不支持该渠道的退款");
            }

            PayRefund payRefund = this.refundOrderHandlerService.createRefundOrder(refundRequest, payChannel);
            if(payRefund == null){
                throw new BusinessException("2006008", "退款申请记录生成失败");
            }

            if (payRefund.getRefundStatus() == RefundStatus.REFUND_EXCEPTION.getValue()) {
                throw new BusinessException("2006008", "退款申请失败");
            } else if (payRefund.getRefundStatus() == RefundStatus.REFUND_CLOSE.getValue()) {
                throw new BusinessException("2006008", "退款已关闭");
            }

            RefundResponse refundResponse = new RefundResponse();
            refundResponse.setRet(Integer.parseInt(ExceptionStatus.SUCCESS.getCode()));
            refundResponse.setMsg(ExceptionStatus.SUCCESS.getMessage());

            JSONObject content = new JSONObject();
            content.put("payment_refund_no", payRefund.getPaymentRefundNo());
            refundResponse.setContent(content);

            return refundResponse;

        } catch (BusinessException e) {

            baseResponse.setRet(Integer.parseInt(e.getCode()));
            baseResponse.setMsg(e.getMessage());
            logger.error("业务异常:code is {},message is {}.", new String[]{e.getCode(), e.getMessage()});
        } catch (Exception e) {

            baseResponse.setRet(Integer.parseInt(ExceptionStatus.E3001001.getCode()));
            baseResponse.setMsg(ExceptionStatus.E3001001.getMessage());
            logger.error("服务端异常", e);
        } finally {
            try {
                redisLockService.unlock(refundKey);
            } catch (Exception e) {
                logger.error("redis 操作异常", e);
            }
        }

        return baseResponse;
    }


    /**
     * 退款查询接口
     *
     * @param refundQueryRequest 下单参数
     * @return BaseResponse
     */
    @Override
    @POST
    @Path("query")
    public RefundQueryResponse refundQuery(RefundQueryRequest refundQueryRequest) {
        String paymentRefundNo = refundQueryRequest.getPaymemt_refund_no();
        String refundTradeId = refundQueryRequest.getRefund_trade_id();
        if (StringUtils.isBlank(refundTradeId) && StringUtils.isBlank(paymentRefundNo)) {
            throw new BusinessException("2001001", "paymemt_refund_no,refund_trade_id 不能同时为空");
        }
        PayRefund payRefund;
        if (StringUtils.isNotBlank(paymentRefundNo)) {
            payRefund = payRefundOrderService.selectRefundByPayRefundNo(paymentRefundNo);
        } else {
            payRefund = payRefundOrderService.selectRefundByRefundTradeId(refundTradeId);
        }

        RefundQueryResponse refundQueryResponse = new RefundQueryResponse();
        try {

            if (payRefund == null) {
                throw new BusinessException("2001001", "退款记录不存在");
            }

            PayDeal payDeal;
            PayChannel payChannel;
            if(StringUtils.isBlank(payRefund.getPayPaymentNo())){
                payDeal = null;
                payChannel = PayChannel.PURSE_BALANCE_PAY;
            }else{
                payDeal = payDealService.queryPayDealByPayPaymentNo(payRefund.getPayPaymentNo());
                payChannel = PayChannel.getPayChannel(payDeal.getPayChannel());
            }

            if (payChannel == null) {
                throw new BusinessException(ExceptionStatus.E2001006.getCode(), "暂不支持该渠道的退款");
            }

            BaseResponse baseResponse = this.refundOrderHandlerService.getRefundChannelHandler(payChannel).refundQuery(payRefund, payDeal);
            BeanUtils.copyProperties(baseResponse, refundQueryResponse);

            JSONObject content = new JSONObject();
            if (baseResponse.getRet() != 0) {
                PayRefund payRefund4response = payRefundOrderService.selectRefundByPayRefundNo(payRefund.getPaymentRefundNo());

                if (payRefund4response.getRefundStatus() <= RefundStatus.REFUND_APPLY.getValue()) {
                    content.put("error_reason", "退款进行中,请等待");
                } else {
                    JSONObject extJson = JSON.parseObject(payRefund4response.getExt());
                    String errCodeDes = extJson.getString("err_code_des");
                    if (StringUtils.isNotBlank(errCodeDes)) {
                        content.put("error_reason", errCodeDes);
                    } else {
                        content.put("error_reason", "账户余额不足或退款已关闭,请联系技术人员确认。");
                    }
                }
            } else {
                content.put("payment_refund_no", payRefund.getPaymentRefundNo());
                refundQueryResponse.setContent(content);
            }
            refundQueryResponse.setContent(content);
        } catch (BusinessException e) {
            refundQueryResponse.setRet(Integer.parseInt(e.getCode()));
            refundQueryResponse.setMsg(e.getMessage());
            logger.error("业务异常:code is {},message is {}.", new String[]{e.getCode(), e.getMessage()});
        } catch (Exception e) {
            refundQueryResponse.setRet(Integer.parseInt(ExceptionStatus.E3001001.getCode()));
            refundQueryResponse.setMsg(ExceptionStatus.E3001001.getMessage());
            logger.error("服务端异常", e);
        }

        return refundQueryResponse;
    }

    /**
     * 退款校验处理
     * @param payDeal          退款记录信息
     * @param refundRequest    请求信息
     * @return                 通过标识
     */
    private boolean payDealCheck(PayDeal payDeal, RefundRequest refundRequest) {

        BigDecimal refundFee = new BigDecimal(refundRequest.getRefund_fee());

        if (StringUtils.isBlank(refundRequest.getPay_payment_no())) {
            throw new BusinessException(ExceptionStatus.E2001006.getCode(), "pay_payment_no 不能为空");
        }

        if (payDeal == null) {
            throw new BusinessException(ExceptionStatus.E2001006.getCode(), "支付记录不存在,请确认支付流水号是否正确");
        }

        if (payDeal.getPayStatus() != PayStatus.PAY_SUCCESS.getValue()) {
            throw new BusinessException(ExceptionStatus.E2001006.getCode(), "支付记录状态不合法");
        }

        if (refundFee.compareTo(payDeal.getReceiveAmount()) > 0) {
            throw new BusinessException(ExceptionStatus.E2001006.getCode(), "本次-退款金额大于支付金额");
        }

        if (StringUtils.isBlank(refundRequest.getNotify_url())) {
            throw new BusinessException(ExceptionStatus.E2001006.getCode(), "退款回调url不能为空");
        }

        List<PayRefund> payRefunds = payRefundOrderService.selectRefundByPayPaymentNo(payDeal.getPayPaymentNo());

        if (payRefunds == null || payRefunds.size() == 0) {
            return true;
        }

        if (refundRequest.getRefund_type() == RefundType.REFUND_ALL.getValue()) {
            throw new BusinessException(ExceptionStatus.E2001006.getCode(), "已存在退款记录  ,不能全单退款");
        }

        BigDecimal allRefundFee = refundFee;
        for (PayRefund payRefund : payRefunds) {
            if (payRefund.getRefundStatus() == RefundStatus.REFUND_ING.getValue() ||
                    payRefund.getRefundStatus() == RefundStatus.REFUND_SUCCESS.getValue()) {

                allRefundFee = allRefundFee.add(payRefund.getRefundAmount());
            }
        }

        if (allRefundFee.compareTo(payDeal.getReceiveAmount()) > 0) {
            throw new BusinessException(ExceptionStatus.E2001006.getCode(), "总-退款金额大于支付金额");
        }

        return true;
    }

    /**
     * 退款查询接口
     *
     * @param refundQueryCheckRequest 下单参数
     * @return BaseResponse
     */
    @Override
    @POST
    @Path("queryCheck")
    public CommonResult queryCheck(RefundQueryCheckRequest refundQueryCheckRequest) {
        Long venderId = refundQueryCheckRequest.getVender_id();
        if(venderId == null){
            refundQueryCheckRequest.setVender_id(this.getVenderId());
        }
        return CommonResult.success(payRefundOrderService.queryCheck(refundQueryCheckRequest));
    }


}
